package com.duojuhe.websocket.socket;

import com.duojuhe.common.constant.SystemConstants;
import com.duojuhe.common.utils.dateutils.DateUtils;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketSession;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class SocketScheduled {
    private ThreadPoolExecutor threadPoolExecutor;
    /**
     * 定时任务线程
     */
    public SocketScheduled() {
        ThreadFactory factory = (new ThreadFactoryBuilder()).setNameFormat("SocketSessionCache-Schedule-Thread" + "-pool-%d").build();
        this.threadPoolExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(), factory);
    }
    /**
     * 检测socket心跳
     */
    @Scheduled(cron = "0 0/1 * * * ? ")
    public void checkClientSocketHeartScheduled() {
       if (!SystemConstants.SYSTEM_INIT_SUCCESS) {
            //项目未初始化成功不执行该定时任务
            log.info("项目未初始化成功不执行该定时任务 ,time={}", new Date());
            return;
        }
        this.threadPoolExecutor.execute(() -> {
            Map<String, SocketSessionUser> clients = SocketSessionCache.getAllSessionUser();
            int closeCount = 0;
            int totalCount = clients.size();
            long allowHeartInterval = 60000;
            for (Map.Entry<String, SocketSessionUser> entry : clients.entrySet()) {
                SocketSessionUser sessionUser = entry.getValue();
                long currentTime = System.currentTimeMillis();
                Date heartDate = sessionUser.getHeartDate();
                long heartTime = heartDate.getTime();
                WebSocketSession session = sessionUser.getSession();
                if (currentTime - heartTime > allowHeartInterval) {
                    log.warn("客户端心跳间隔超过{}秒, 最后心跳时间={}, sessionId={}, ip={}", allowHeartInterval / 1000, DateUtils.dateToString(heartDate, "yyyy-MM-dd HH:mm:ss.SSS"), session.getId(), SocketUtil.getClientIp(session));
                    if (!sessionUser.getThreadPoolExecutor().isShutdown()) {
                        sessionUser.getThreadPoolExecutor().shutdownNow();
                    }
                    try {
                        sessionUser.getSession().close(CloseStatus.SERVICE_RESTARTED);
                    } catch (Exception e) {
                        log.error("客户端长时间没有发送心跳包，系统尝试关闭socket失败", e);
                    }
                    closeCount++;
                }
            }
            log.info("客户端连接状态检测结果，总共{}个连接，心跳超时连接共{}个",totalCount, closeCount);
        });
    }
}
